package com.weigecoder.warehouse.service.impl;

import com.alibaba.fastjson.JSON;
import com.weigecoder.warehouse.constant.WarehouseConstants;
import com.weigecoder.warehouse.dto.AssignAuthDto;
import com.weigecoder.warehouse.dto.AssignAuthToUserDto;
import com.weigecoder.warehouse.entity.Auth;
import com.weigecoder.warehouse.entity.Role;
import com.weigecoder.warehouse.mapper.AuthMapper;
import com.weigecoder.warehouse.mapper.RoleMapper;
import com.weigecoder.warehouse.service.AuthService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
public class AuthServiceImpl implements AuthService {

    @Autowired
    private AuthMapper authMapper;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private RoleMapper roleMapper;

    /**
     * 根据用户ID查询用户权限菜单树
     *
     * @param userId
     * @return
     */
    @Override
    public List<Auth> findAuthTreeByUserId(int userId) {
        //先从redis查缓存，查到权限菜单树转成的json串
        String authTreeListJson = redisTemplate.opsForValue().get(WarehouseConstants.AUTH_TREE_PREFIX + userId);
        //redis中查到缓存
        if (StringUtils.hasText(authTreeListJson)) {
            //将json串转回权限(菜单)树List<Auth>并返回
            List<Auth> authTreeList = JSON.parseArray(authTreeListJson, Auth.class);
            return authTreeList;
        }
        //redis中没有查到缓存,从数据库表中查询所有权限(菜单)
        List<Auth> allAuthList = authMapper.findAllAuthByUserId(userId);
        //将所有权限(菜单)List<Auth>转成权限(菜单)树List<Auth>
        List<Auth> authTreeList = allAuthToAuthTree(allAuthList, 0);
        //将权限(菜单)树List<Auth>转成json串并保存到redis
        redisTemplate.opsForValue().set(WarehouseConstants.AUTH_TREE_PREFIX + userId, JSON.toJSONString(authTreeList), 3600 * 24, TimeUnit.SECONDS);
        //返回权限(菜单)树List<Auth>
        return authTreeList;
    }

    /**
     * 将所有权限(菜单)转成权限(菜单)树的递归算法
     *
     * @param allAuthList
     * @param parentId
     * @return
     */
    private List<Auth> allAuthToAuthTree(List<Auth> allAuthList, int parentId) {
        //获取父权限(菜单)id为参数parentId的所有权限(菜单)
        //【parentId最初为0,即最初查的是所有一级权限(菜单)】
        List<Auth> firstLevelAuthList = new ArrayList<>();
        for (Auth auth : allAuthList) {
            if (auth.getParentId() == parentId) {
                firstLevelAuthList.add(auth);
            }
        }
        //查询List<Auth> authFirstListTree中每个权限(菜单)的所有二级菜单【子级权限(菜单)】
        for (Auth firstAuth : firstLevelAuthList) {
            List<Auth> childAuthList = allAuthToAuthTree(allAuthList, firstAuth.getAuthId());
            firstAuth.setChildAuth(childAuthList);
        }
        return firstLevelAuthList;
    }


    /**
     * 查询整个权限(菜单)树的业务方法
     */
    @Override
    public List<Auth> allAuthTree() {
        //先从redis中查询缓存,查到的是整个权限(菜单)树List<Auth>转的json串
        String allAuthTreeJson = redisTemplate.opsForValue().get("all:authTree");
        if (StringUtils.hasText(allAuthTreeJson)) {//redis中查到缓存
            //将json串转回整个权限(菜单)树List<Auth>并返回
            List<Auth> allAuthTreeList = JSON.parseArray(allAuthTreeJson, Auth.class);
            return allAuthTreeList;
        }
        //redis中没有查到缓存,从数据库表中查询所有权限(菜单)
        List<Auth> allAuthList = authMapper.getAllAuth();
        //将所有权限(菜单)List<Auth>转成整个权限(菜单)树List<Auth>
        List<Auth> allAuthTreeList = allAuthToAuthTree(allAuthList, 0);
        //将整个权限(菜单)树List<Auth>转成json串并保存到redis
        redisTemplate.opsForValue().set(WarehouseConstants.ALL_AUTH_TREE, JSON.toJSONString(allAuthTreeList), 2, TimeUnit.DAYS);
        //返回整个权限(菜单)树List<Auth>
        return allAuthTreeList;
    }


    /**
     * 给角色分配权限(菜单)
     * //事务处理
     * @param assignAuthDto
     */
    /**
     * 清理用户权限树，否则有缓存，查询不到新的权限  (或者提示24小时后有效)
     * @param assignAuthDto
     */
    @Transactional
    @Override
    public void assignAuth(AssignAuthDto assignAuthDto) {

        //拿到角色id
        Integer roleId = assignAuthDto.getRoleId();
        //拿到给角色分配的所有权限(菜单)id
        List<Integer> authIds = assignAuthDto.getAuthIds();

        //根据角色ID查询拥有该角色的所有用户的ID
        List<Integer> userIds = roleMapper.selectAllUserIdsByRoleId(roleId);
        ArrayList<String> newUserIds = new ArrayList<>();

        for (Integer userId : userIds) {
            newUserIds.add(WarehouseConstants.AUTH_TREE_PREFIX+userId);
        }
       //清理有该角色下的所有用户权限的缓存
        redisTemplate.delete(newUserIds);

        //根据角色id删除给角色已分配的所有权限(菜单)
        authMapper.delAuthByRoleId(roleId);
        //循环添加角色权限(菜单)关系
        for (Integer authId : authIds) {
            authMapper.insertRoleAuth(roleId, authId);
        }
    }


    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    /**
     * 修改用户权限的业务 ，还是个问题
     * 前端传过来用户的ID和修改权限的ID集合，
     * 后端接收之后封装到dto，根据userid获取用户的角色，
     * 删除该角色已分配的权限，然后修改重新分配权限
     *
     * @param assignAuthToUserDto
     */
    @Transactional
    @Override
    public void assignAuthToUser(AssignAuthToUserDto assignAuthToUserDto) {
        Integer userId = assignAuthToUserDto.getUserId();
        List<Integer> authIds = assignAuthToUserDto.getAuthIds();
        //角色集合
        List<Role> roles = roleMapper.selectRolesByUserId(userId);

        //角色ID集合
        List<Integer> roleIds = new ArrayList<>();

        for (Role role : roles) {
            roleIds.add(role.getRoleId());
        }
        //删除权限缓存
        stringRedisTemplate.delete(WarehouseConstants.AUTH_TREE_PREFIX+userId);
        //根据角色删除给角色已分配的所有权限(菜单)
        authMapper.delAuthByRoleIds(roleIds);

        /**
         * 直接更改权限 ，角色信息不变
         */

        //循环添加角色权限(菜单)关系
        for (Role role : roles) {
            for (Integer authId : authIds) { // 28,29,27,30
                authMapper.insertRoleAuthByRoleIdAndAuthId(role.getRoleId(), authId);
            }
        }

    }
}
